home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
HPAVC
/
HPAVC CD-ROM.iso
/
VGOVBE20.ZIP
/
VGOVBE20.TXT
< prev
Wrap
Text File
|
1997-03-24
|
24KB
|
543 lines
─────────────────────────────────────────────────────────────────────────────
VGOVBE20.TXT - Vesa 2.0 implementation, activation, and just plain how
it works.
─────────────────────────────────────────────────────────────────────────────
Doc by: Vector/Vertigo
Code by: TimJ/Vertigo
If I were TimJ a quote would go here....
Vertigo Webpage = http://demoscene.interstat.net/~vertigo/
email: tim@legend.co.uk = TimJ
cowan@gold.guate.net = Vector
irc: #coders #vertcode
revision history:
24/03/97 v1.0 - Initial version
─────────────────────────────────────────────────────────────────────────────
INTRODUCTION
─────────────────────────────────────────────────────────────────────────────
Well, it's been about a month since TimJ released vgophong.doc, and we
decided it was time to release a few more tutorials (two in fact). These
tutorials should be pretty messed up, since I am writing a tutorial on
TimJ's Vesa code, and he is writing one on my faith code ;).
The reason of this tut is because lately the trend has been moving on to
Vesa 2.0. Vesa 2.0 is a standard that enables all cards to be able to do
certain acts, using the same exact functions. These commands are quite basic,
but very powerful. One can use high resolutions and high colors, just as easy
as writing to the normal VGA mode 13h.
Unfortunately, there is no good documentation out there on how to set
the Vesa 2.0 modes ( which are a little harder to set than mode 13h ;).
There are a few libraries out there that give the user the functions to set
Vesa 2.0. But obviously most people out there don't want to have to kludge
in someone elses libraries just to use this. Also, many people who do manage
to set the modes, notice that for some reason their code is very buggy.
This is usually because they forgot to set LFB, remap the LFB, check to see
if the mode is available, or even if they are setting the right mode.
─────────────────────────────────────────────────────────────────────────────
BEFORE WE START
─────────────────────────────────────────────────────────────────────────────
This TXT assumes that you have knowledge of working with VGA mode 13h and
protected mode. Also, some knowledge of assembler would be beneficial =).
The PMode Header you use MUST support DPMI function 800h. (DOS32 Free Version
does not=( ).
If you want to use the included source, you should have an assembler (it
has been tested with TASM 3.1 and TASM 5.0). But just in case, I have also
included an .OBJ file. Also included is a C header file, so that this may
be included in your C/C++ programs. Finnally, a 2 short C programs have been
included, to show a bit on the use of the code (They have been tested with
Watcom C 10.5a and 10.6).
Also, This Document and its companion code is provided free, and as-is.
Put all that other disclaimer junk here too... oh, if any harm comes to your
machine from this, then send flames to president@whitehouse.gov . We are not
responsible =).
─────────────────────────────────────────────────────────────────────────────
WHAT WE WANT
─────────────────────────────────────────────────────────────────────────────
First lets ask ourselves, what would the perfect Vesa 2.0 mode setting
library do for us? Well this is what we need:
A) Most important, we want usage of an LFB (Linear Frame Buffer). This
allows us to write to video memory just as easy as writing to mode 13h.
I read in imphobia that All PCI video cards support LFB, and most cards
found on 486's support it, so requiring support for bank switched
modes should not be neccessary (Thank god).
B) We want to remap this LFB to usable memory. Most times the Vesa mode
will work without doing this, but we should do this to get 100%
compatibility.
C) We also want good error detection. Like selecting an unavailable mode,
and detecting to see if Vesa 2.0 is available.
D) The interface should be easy & intuitive. Instead of selecting a mode,
we should pass an X resolution, Y resolution, and Bit Depth. Not only is this
easier, but the vesa standard states that modes do not need be static. So in
the future, mode 147h may not always be 320*240*32Bits.
E) We want to receive as much information as possible. We want to know how
many bits are R,G, and B, where they start, and what order they are in.
we want to know how much available video memory there is, etc....
─────────────────────────────────────────────────────────────────────────────
WHAT TO DO
─────────────────────────────────────────────────────────────────────────────
Okey, first, lets lay out the functions we are going to make:
-= VBEINFO *vbeDetect(void) =-
This will detect to see if Vesa 2.0 is available, and return information
on the video card.
-= long vbeGetModeInfo(int mode,VBEMODEINFO *bla) =-
This will get every bit of info on a video mode, resolution, depth, video
window stuff, bit organizing, etc... and return it into bla. It will return
a 1 on success (Mode found, etc..) and 0 on failure.
-= VBESURFACE *vbeOpen(long X,long Y,long BPP) =-
This will actually set the mode. It will set an X*Y*BPP mode (BPP being
bits per pixel, not bytes). It will return a pointer to VBESURFACE,
containing the location of LFB, the actual mode number, bits & bytes per
pixel,etc...
-= vbeClose(VBESURFACE *bla) =-
Of course we need to close the mode. This will get rid of all the vbe stuff,
and return us to good old mode 3h.
-= vbeSetScanWidth(long width) =-
This function will set the logical scanline width of video memory. This way
we can set how far we can horizontally scroll. Remember, to set a pixel its
(x+(y*logicalWidth)) not (x+(y*screenWidth)) Unless you make them the same.
Which for starting out, we will. We will set this in pixels.
-= long vbeGetScanWidth(void) =-
This function returns the logical scan width. We will get this in pixels.
-= vbeSetStart(long X,long Y) =-
This will flip the screen to a certain X and Y position in video memory.
Very usefull for page flipping and scrolling.
-= vbeGetStart(int *X, int *Y) =-
This will return the screens logical X & Y position in video memory.
-= vbeVR() and vmode(int mode) =-
Complimentary functions that wait for the vertical retrace (So there is no
screen shearing) and set a standard vga mode respectively.
─────────────────────────────────────────────────────────────────────────────
LETS START THE CODE
─────────────────────────────────────────────────────────────────────────────
Please note, I will not list the structures here, as they are VERY commented
in the code, and quite large. I also won't go through the code step by step,
but rather explain what is happening. I would recommend either printing the
code up, or having it on hand in another window.
Also note that we are going to be calling most functions through real mode,
this is because many VBE functions require the real mode trait of passing
pointers through ES:DI.
DPMI Interrupts
~~~~~~~~~~~~~~~
First, I should probably list the DPMI interrupts we are going to use:
(All DPMI interrupts use INT 31h)
-= Allocate Dos Memory =-
AX = 0100h
BX = # of paragraphs to allocate. (A paragraph is 16 bytes)
Returns:
AX = Real mode segment of Block.
DX = Selector for the allocated block.
CF = 0 on success,1 on error
We are going to need this function to allocate memory for our information
blocks. Like VBEINFO and such.
-= Free Dos Memory =-
AX = 0101h
DX = Selector of Block
Return
CF = 0 on success, 1 on error
Free the memory we just allocated of course.
-= Simulate Real Mode Interrupt =-
AX = 0300h
BL = Interrupt number
BH = should be kept to 0.
CX = Number of words to copy from protected to Real mode stack.
ES:DI = selector:offset or RM structure (See RMREGS in asm code)
Returns:
RMREGS = Filled with return info
CF = 1 on error, 0 on success
We need this function to make real mode calls from protected mode.
-= Physical Address Mapping =-
AX = 0800h
BX:CX = Physical address we want to map.
SI:DI = Size we want to map
Return:
CF = 0 on success, 1 on error
BX:CX = linear address that maps the memory
This function is very helpfull, because it lets us write to memory we
normally wouldnt be able to reach. Since a video card mey be crazy
enough to put its LFB out there ;).
- Free Physical Address Mapping -
AX = 0801h
BX:CX = Address returned by function 0800h.
Return
CF = 0 on success, 1 on error.
Free up the memory we mapped, like the good coders we are =).
VBE Interrupts
~~~~~~~~~~~~~~
Now that we have the DPMI interrupts out of the way, I will state the VBE
interrupts we will be using. Remember that some of them will be called
through a real mode interrupt. All Vesa interrupts use INT 10h.
VBE instructions will always return 04Fh in EAX. if a VBE function does not
return this, it means there was an error (VBE driver not loaded and such).
-= Return VBE controller Info =-
AX = 4F00h
ES:DI = Pointer to 512 Allocated bytes to put VbeInfoBlock
This function will put a lot of info about the video card into a VbeInfoBlock
pointed to by ES:DI (So it needs to be called from real mode).
Remember to set VbeSignature inside VbeInfoBlock to 'VBE2'. This will tell
the interrupt that we want vbe2.0 information returned. After the Int is
called, 'VESA' should be returned in VBE Signature. To see everything
returned, check the VbeInfoBlock structure in the code.
-= Return VBE Mode Info =-
AX = 4F01h
CX = Mode Number
ES:DI = Pointer to ModeInfoBlock structure.
This will fill up a ModeInfoBlock pointed to by ES:DI (also needs to be
called from RM) with all sorts of goodies about the mode in CX. To see
everything returned, please check ModeInfoBlock structure inside the code.
-= Set VBE Mode =-
AX = 4F02h
BX = Mode Number. Bits 9-13 must be 0. OR bit 14 with 1 to indicate we
want to use LFB. OR bit 15 with 1 to clear video memory.
Here is the Actual meat of the modeSetting. You will notice that there is no
structure passed here. That is because all the info on the mode is obtained
through Function 4F01h (Like LFB location and stuff).
Notice that since we don't need to pass info through ES:DI this function can
be called Directly.
-= Get/Set Display Start =-
AX = 4F07h
CX = First Displayed Pixel Scanline (X pos)
DX = First Displayed Scanline (Y pos)
BH = Must be kept to 0
BL = 0 to set display, 1 to get display, 80h=Set during V. Retrace.
Return:
AX = VBE return status (Returned in ALL functions)
BH = Always 00h.
CX = First Displayed Pixel Scanline (On get display)
DX = First Displayed Scanline (On get display)
Imagine the screen as a small rectangle, held completely inside a larger
rectangle (video memory). This function will move the little rectangle around
the big rectangle very smoothly. This allows such things as page flipping,and
scrolling at very high speeds. This same function is also used to get the
location of the screen in memory, by setting BL to 1.
-= Get/Set Logical Display Width =-
AX = 4F06h
BX = 0 to set width in pixels, 2 to set width in bytes,
1 to get width, 3 to get maximum width.
CX = Width in pixels (Or bytes, depending upon BX) to set width.
Return:
AX = VBE return status (returned in ALL functions)
BX = Width in bytes of scanline.
CX = Width in pixels.
DX = Maximum number of scanlines.
This sets or gets the width we want the big rectangle of video memory holding
our screen to be. This way we can scroll horizontally as well as vertically.
The only problem with this is that finding Y coordinates varies with the
logical scanline width. (PixelPos= x+(y*LogicalWidth))
______________________
Whats In The Functions
~~~~~~~~~~~~~~~~~~~~~~
It feels good to get all those damn interrupts out of the way. Now I can
safely explain all the functions in pseudocode. After this, you should be
able to piece the actual ASM code together with this pseudocode quite
smoothly.
-= VBEINFO *vbeDetect(void) =-
start:
'DPMI 100h' Get memory to put vbeInfo Block into
Ready RmRegs for 'VBE 4F00h'
Put VBE2 into vbeInfo.VbeSignature
'DPMI 300h' Call VBE 4F00h in real mode.
Check to see If everything ok.
'DPMI 101h' Free the vbeInfoBlock
end:
-= int vbeGetModeInfo(int mode,VBEMODEINFO *bla) =-
start:
call VbeDetect JIK
'DPMI 100h' Get memory to put modeInfo Block into
Ready RMREGS for 'VESA 4F01h'
'DPMI 300h' to call VBE 4f01h in real mode
move everything from modeInfo Block to bla
free modeInfo Block with 'DPMI 101h'
return Success
End:
-= VBESURFACE *vbeOpen(int X,int Y,int BPP) =-
start:
Make sure we arent already in a vesa mode
call VbeDetect JIK
'DPMI 100h' to allocate for ModeInfo block (To check every available mode)
Go through all available modes returned by VbeDetect until finding a match
OR the Mode found with 4000h to say we want LFB
If It worked, map the LFB memory to accessible memory with 'DPMI 800h'
Set vbeInit variable so from now on we know a mode is set
Make sure logical scanline width is equal to screen scanline width.
Set everything in the return structure
end:
-= vbeClose(VBESURFACE *bla) =-
start:
Check to see if a vbe mode is set
Free the mapped LFB memory with 'DPMI 801h'
Set VGA mode 0x3h
end:
Almost direct functions:
-= vbeSetScanWidth(int width) =-
Set logical screen width in pixels, with 'VBE 4F06h'
-= int vbeGetScanWidth( void) =-
Get logical screen width in pixels, with 'VBE 4F06h'
-= vbeGetStart(int *X, int *Y) =-
Get logical screen pos with 'VBE 4f07h'
-= vbeSetStart(int X, int Y) =-
Set logical screen pos with 'VBE 4f07h'
We are done with the Code!
~~~~~~~~~~~~~~~~~~~~~~~~~~
Well, you should be able to piece everything together by now. If not, don't
worry, take a breather and read over a nice refreshing 386 asm manual with a
nice glass of pepsi.
─────────────────────────────────────────────────────────────────────────────
NOW HOW DO I PUT THE CODE IN?
─────────────────────────────────────────────────────────────────────────────
Now that you have the asm at hand, and understand it, it is time to get using
Vesa 2.0. First, lets get the thing to compile. It should go in as easy as
a snap of your fingers, just include the ASM in your makefile, or the .OBJ
in your project file (Or .asm if the project manager is set to a compatible
assembler). After that, just include the .h in your C files. If you want to
use the functions in other ASM programs, make sure to mark them as External
wherever you use them.
If you get any troubles with tasm, the switches I use are:
tasm -q -p -t -ml -zi -m3 vgovbe20
To compile the simple C example file, if you have Watcom, you can run
M.bat and then run test.exe.
─────────────────────────────────────────────────────────────────────────────
COOL! IT COMPILES! NOW HOW DO I USE THEM?
─────────────────────────────────────────────────────────────────────────────
Well, ill explain how in C (Im sure everyone who uses ASM can figure this
out ;). First off, you probably want to call vbeDetect, to see if everything
is in there fine.
After that, we can set any mode with ease. Just make sure to have
VBESURFACE *myScreen; defined. (Make sure to see the VBESURFACE struct
in the .H file).
After that, just call myScreen = vbeOpen(X,Y,BPP);
X=The x resolution you want, Y=duh, BPP is the bits per pixel to use.
--BPP can normally be one of:
4 = 16 palleted colors,
8 = 256 palleted colors,
15 = 5.5.5.1 RGBA colors.
16 = (Arbitrary, but I think UniVBE always sets this to 5.6.5) RGB colors
24 = 8.8.8 RGB Colors.
32 = 8.8.8.8 RGBA colors.
To actually plot a pixel is as simple as writing to mode 13h, except the
screen isnt static at 0A0000h. Just get the screen pointer from myScreen.LFB;
after that, you are free to play around =).
--Lets do a few Experiments with High/True color:
Remember how in paletted 13h to write a white pixel, you would get whatever
palette entry was white and write that? Well now you basically write that
palette straight to the screen.
In 24bit mode, the screen is layed out as:
byte =0,1,2,3,4,5,6,7,8 957,958,959
|B G R|B G R|B G R|...............|B G R|
pixel= 1 , 2 , 3 , 319
So, to write a white pixel to the screen in 24 bit value, you would do:
(char *)(myScreen)[0]=255; //Write Blue value of pixel 0
(char *)(myScreen)[1]=255; //Write Green value of pixel 0
(char *)(myScreen)[2]=255; //Write Red value of pixel 0
//Next pixel starts at [3], if 32bit mode, next pixel would be at [4].
You probably noticed 2 things. One is that the screen is layed out with first
byte being B, then G, then R (Instead of RGB) (Some cards have the ability to
flip this around, but I have never come across this, same as non 565 16bit
modes. just to be safe, check the mode after you set it). Another thing is
that 24bit mode is a bitch. It's no fun having to write byte by byte.
Thats why 32Bit mode was invented, it is much faster, because you can write
a Dword at a time, except you have that Alpha byte at the end. (An alpha byte
is a padding byte, this byte doesnt neccessarilly need to be wasted memory,
You can store many things in here if you put your mind to it).
Anyways, to set a white pixel in 32bit mode, you can do this:
(long *)(myScreen)[0] = 00FFFFFFh
Whats real cool, is that you can set the pixel real easy in hex, by splitting
the number up like so:
|00 |FF |FF |FF |
A R G B
To use high color (15/16 bit modes) Is a tiny bit trickier, but if you use
them right, they can actually be faster since there is much less data to
move.
A white pixel in 16BIT mode= (short *)(myScreen)[0] = FFFFh
and 15bit mode= (short *)(myScreen)[0] = 7FFFh (can also be FFFFh).
The formula to convert a 24bit pixel to a 16bit pixel is:
(short *)(myScreen)[0] = ((char *)(yourScreen)[0]>>3) |
(((char *)(yourScreen)[0]<<3)&7E)|
(((char *)(yourScreen)[0]<<8)&F8);
It may seem annoying at first, but once you get it integrated into your
functions it starts to become automatic. (Just don't call a 24to16bit
conversion every pixel!)
One last cool thing I want to mention, is that you can do REAL fast 50%
transparencies in True/High color using bit-wise operations. Simply do this:
For 32Bit mode:
--------
//PixelA = source pixel. PixelB=Destination pixel
pixelA >>=1; //Divide the pixel values in half
pixelB >>=1;
pixelA &=0x7F7F7F7F; //Clear the residual bit
pixelB &=0x7F7F7F7F;
//By now pixelA & Bs maximum R,G,and B values are 7F=127 out of 255.
pixelB +=pixelA;
//Now pixelB is equal to A+B transparency.
-------
For 16Bit mode:
--------
//PixelA = source pixel. PixelB=Destination Pixel
pixelA >>=1; //Divide the pixel Values in half
pixelB >>=1;
pixelA &=0x7FEB; //Clear the residual bit
pixelB &=0x7FEB;
//By now pixelA & Bs maximum R,G,and B values are 7F=127 out of 255.
pixelB +=pixelA;
//Now pixelB is equal to A+B transparency.
-------
With this you can do many effects, such as Motion Blur (By recursively making
one screen transparent over the other with 2 screen buffers, and fliping
which one you write to). Or quick transparencies.There are many other effects
you can do with bitwise operations, Enjoy =). Thanks very much to Brazil for
showing me this previous technique when I started Vesa coding last year.
─────────────────────────────────────────────────────────────────────────────
WELL, IM ALL SET TO GO, ANYTHING ELSE I SHOULD BE AWARE OF?
─────────────────────────────────────────────────────────────────────────────
Yes actually, a few things:
A) Even though it's not neccessary, you should do a vbeGetModeInfo mode after
you set a mode, do this to ensure a few things: If you are doing a 16bit mode
to, see if it's 5.6.5(if not either quit, or adjust your functions) And check
to see if the screen is ordered BGR not the other way around. I have actually
never encountered these problems, but there are cards that have options to
change this, and VBE specs say it is liable to happen. (Although I think
UNIVBE always makes this BGR & 5.6.5)
B) Under most cases, write to an Offscreen buffer and copy to screen. This
is because reading from video memory is PAINFULLY slow. Here is where the
biggest benefits of using 16bit VS 32bit pay off.
C) If you are going to clear the screen, I have found it much faster to clear
with the FPU. Although copying with FPU seems to be slower (Because of
reading Invalid FPU numbers (NaN)). Try and see, different people get
different results.
D) UniVBE is actually real nice, It does many things for you like make sure
LFBs are Always available, for any and every card. It also makes sure 16bit
modes are always 5.6.5 and data is organized in BGR fashion. Univbe does have
an option for switching this... but thats the users fault ;).
─────────────────────────────────────────────────────────────────────────────
HOW COULD I MAKE THIS VBE20 LIBRARY BETTER?
─────────────────────────────────────────────────────────────────────────────
Well, many ways. I originally set this document to teach VBE mode setting
only (VBE function 4f07h was just a bonus ;). There are still many ways you
can make this better:
A) We had an A), but we put this in for you, ain't that sweet? =).
B) Get support for VBE/AF (accelerator functions) in there. Unfortunately
we haven't been able to try these out since uniVBE currently only provides
this for the MACH64 video card. These functions should allow us to use
3D and 2D accelleration features as easily (?) as setting vesa modes are now.
C) Actually make it a library ;) This is by far not complete. Add function
pointers to different 2D primitives according to the mode. Or go full steam
ahead and make a full OOP engine. The sky is the limit.
─────────────────────────────────────────────────────────────────────────────
THE LAST WORD
─────────────────────────────────────────────────────────────────────────────
It's now 5:30AM and I haven't slept for like 24 hours, so I better go get
some coffee and stay awake... just not writing tutorials where not writing
coherently can make universes collide. Wow... the keys on my keyboard look
all fuzzy and wavy... must 7BEF em... This is the reason there were no
ASCII pictures in here =). Hopefully the descriptions where good enough
where you did not need them.
If you got any use out of this Tutorial or this code, make sure to email us
and/or greet us in your productions, it's all we ask =). If you want more
information on the VBE, make sure to download the oficial VBE specs at
www.scitechsoft.com and many other popular places. If you want more help,
I have released the source to my truecolor 4K intro 'Faith', which should be
available on hornet (ftp.cdrom.com/pub/demos). This intro shows how to do
more advanced true-color tricks than the included test.c.
Finally I want to thank TimJ for giving me the original VBE code way back,
which helped me through a lot of bugs that would have taken a long time to
figure out otherwise. All the attached code was done by him, and without it,
this DOC probably wouldn't have existed.
Greets:
Everyone else In Vertigo, Vastator the typo tamer(Just a little too late)
Midnight, Fysx, Phred, GooRoo, Vor, Brazil, God, MrData, Grimace...
These fly out to many people, please check the our web pages greet list,
being greeted in there is just as good as being greeted in all of our
productions ;).
Peace & Werd or something...
Vector/Vertigo